import { MetaclassType } from "@/mdesign-lib/mdesign-app.umd.js";
import { PropertyRow, ModelValue } from "@/mdesign-lib/mdesign-app.umd.js";

import { PropertyKey, ModelType, PropertyDataType } from "@/mdesign-lib/mdesign-app.umd.js";
import { modelService } from "@/mdesign-lib/mdesign-app.umd.js";
import { StType } from "@/mdesign-lib/mdesign-app.umd.js";
import { ExtraAttribute } from "@/mdesign-lib/mdesign-app.umd.js";

export interface HighLightContent {
  text: string;
  unit?: string;
  icon?: string;
  isModel?: boolean;
  modelId?: string;
  isItemFlow?: boolean;
  isBool?: boolean;
  prefix?: string;
  isSelect?: boolean;
  enName?: string;
  direction?: "left" | "right";
}

// 提取单元格信息用做搜索高亮
export const getHighLightValue = (row: PropertyRow) => {
  let value = row.value;
  let dataType = row.dataType;
  if (row.key === PropertyKey.NamedElement_name || row.specificComponent === PropertyKey.NamedElement_name) {
    const extraInfo = row.extraInfo;
    const prefix = extraInfo?.showAttribute?.extraAttribute?.requirementId;
    let icon = extraInfo?.icon ? modelService.getModelIcon(app.activeProject!.id, extraInfo?.icon) : "";
    return [{ text: value as string, icon: icon, prefix }];
  } else if (row.key === PropertyKey.Element_activeHyperLink) {
    let icon = "";
    if (!value) {
      value = "";
    } else {
      const hyperlinkValue = JSON.parse(value as string);
      value = hyperlinkValue.name || "";
      icon = hyperlinkValue.icon || "";
    }
    return [{ text: value as string, icon: icon }];
  } else if (row.key === PropertyKey.PartICDTable_itemFlow || row.key === PropertyKey.WhiteBoxICDTable_itemFlow) {
    const result = row.extraInfo?.itemFlowValue || [];
    return result;
  } else if (row.key === PropertyKey.InstanceSpecification_slot) {
    if (Array.isArray(value)) {
      const result: any[] = [];
      value.forEach(item => {
        const text = item.showAttribute?.extraAttribute?.slotLabel || "";
        const icon = item.icon || "";
        result.push({ text, icon });
      });
      return result;
    }
  } else if (row.slotId || row.propertyId) {
    if (row.propertyId) {
      row.modelId = row.propertyId;
    }
    if (!row.values) return [];
    if (row.dataType === PropertyDataType.INSTANCE) {
      value = row.values as ModelValue[];
    } else {
      value = row.values.map(item => item.value);
    }
  } else if (row.key === PropertyKey.Element_ownedElement && row.dataType === PropertyDataType.INSTANCE) {
    if (Array.isArray(value)) {
      const metaclassTypes = value.map(item => item.metaclass);
      if (metaclassTypes.length > 0) {
        const allMetaclassTypes = [
          MetaclassType.LiteralInteger,
          MetaclassType.LiteralBoolean,
          MetaclassType.LiteralString,
          MetaclassType.LiteralReal,
          MetaclassType.ElementValue,
          MetaclassType.StringExpression,
          MetaclassType.InstanceValue,
          MetaclassType.LiteralUnlimitedNatural,
          MetaclassType.OpaqueExpression
        ];
        const exist = allMetaclassTypes.includes(metaclassTypes.last());
        if (exist) {
          const result: any[] = [];
          value.forEach(item => {
            const text = (item.showAttribute?.extraAttribute?.value || "") + "";
            const icon = item.icon || "";
            result.push({ text, icon });
          });
          return result;
        }
      }
    }
  }

  if (row.valueSpecificationInfo) {
    const metaclassType = row.valueSpecificationInfo.metaclass;
    if (metaclassType === MetaclassType.ElementValue || metaclassType === MetaclassType.InstanceValue) {
      dataType = PropertyDataType.INSTANCE;
      value = row.valueSpecificationInfo.element;
    } else if (metaclassType === MetaclassType.LiteralBoolean) {
      dataType = PropertyDataType.BOOLEAN;
      value = row.valueSpecificationInfo.value;
    } else if (metaclassType === MetaclassType.LiteralNull) {
      dataType = PropertyDataType.STRING;
      value = "Null";
    } else {
      dataType = PropertyDataType.STRING;
      value = row.valueSpecificationInfo.value.toString();
    }
  }
  //
  switch (dataType) {
    case PropertyDataType.BOOLEAN:
      if (row.isMultiplicity) {
        return (value as string[]).map(valueItem => {
          // return { text: valueItem !== null ? valueItem ? '是' : '否' : '', isBool: true };
          let text = "";
          if (valueItem !== null) {
            text = valueItem ? "true" : "false";
          }
          return { text, isBool: true };
        });
      } else {
        let text = "";
        if (value !== null) {
          text = value ? "true" : "false";
        }
        return [{ text, isBool: true }];
      }
    case PropertyDataType.REAL:
    case PropertyDataType.INTEGER:
    case PropertyDataType.UNLIMITEDNATURAL:
    case PropertyDataType.STRING:
      if (row.isMultiplicity) {
        return (value as string[]).map(item => {
          return { text: item !== undefined && item !== null ? item.toString() : "", unit: row.unit };
        });
      } else {
        if (value === null) {
          value = "";
        }
        return [{ text: value.toString() }];
      }
    case PropertyDataType.ENUM:
      if (row.isMultiplicity) {
        if (Array.isArray(row.items)) {
          // 下拉选项模式
          const itemObj = {};
          row.items.forEach(item => {
            itemObj[item.value] = item;
          });
          return (value as string[])
            .filter(valueItem => !!valueItem)
            .map(valueItem => {
              const currentItem = itemObj[valueItem];
              return { text: currentItem.label, icon: currentItem.icon, isSelect: true, enName: currentItem.enLabel };
            });
        }
      }
      return [];
    case PropertyDataType.INSTANCE:
      if (row.isMultiplicity) {
        if (value === null) {
          return [];
        }
        return (value as ModelValue[]).map(item => {
          return {
            text: getModelLabel(item),
            icon: item.icon,
            isModel: true,
            modelId: item.id,
            prefix: item.showAttribute?.extraAttribute?.requirementId
          };
        });
      } else {
        if (Array.isArray(row.items)) {
          // 下拉选项模式

          const itemId = value ? (value as ModelValue).id : "";
          const currentItem = row.items.filter(item => item.value === itemId)[0];
          if (currentItem) {
            return [{ text: currentItem.label, icon: currentItem.icon, isSelect: true, enName: currentItem.enLabel }];
          } else {
            return [];
          }
        } else {
          let currentValue = value as ModelValue;
          return currentValue
            ? [
                {
                  text: getModelLabel(currentValue),
                  icon: currentValue.icon,
                  isModel: true,
                  modelId: currentValue.id,
                  prefix: currentValue.showAttribute?.extraAttribute?.requirementId
                }
              ]
            : [];
        }
      }

    default:
      return [];
  }
};

export const getModelLabel = (modelValue: ModelValue) => {
  const sts = modelValue.baseSt || modelValue.metaclass;
  let label = modelValue.name || "";
  const propertyType = new Set([
    MetaclassType.Property,
    MetaclassType.Port,
    StType["SysML::DeprecatedElements::FlowPort"],
    StType["SysML::PortsAndFlows::FullPort"],
    StType["SysML::PortsAndFlows::ProxyPort"],
    StType["Customization::ConstraintProperty"],
    StType["SysML::PortsAndFlows::FlowProperty"],
    StType["Customization::PartProperty"],
    StType["SysML::Blocks::ParticipantProperty"],
    StType["Customization::ReferenceProperty"],
    StType["Customization::moe"],
    StType["Customization::ValueProperty"],
    StType["Customization::ConstraintParameter"]
  ]);
  if (modelValue.type === ModelType.Relation) {
    label = getRelationLabel(modelValue);
  } else if (propertyType.has(sts as StType)) {
    label = getPropertyLabel(modelValue);
  } else if (sts === MetaclassType.InstanceSpecification) {
    label = getInstanceSpecificationLabel(modelValue);
  } else if (sts === MetaclassType.Slot) {
    label = getInstanceLabel(modelValue);
  }

  return label;
};

const getRelationLabel = (modelValue: ModelValue) => {
  const sperator = modelValue.showAttribute?.isDirection ? "→" : "-";
  return (
    modelValue.modelTypeCnName +
    `${modelValue.name ? " : " + modelValue.name : ""} [ ${modelValue.showAttribute?.sourceName || ""} ${sperator} ${
      modelValue.showAttribute?.targetName || ""
    } ]`
  );
};

const getPropertyLabel = (modelValue: ModelValue) => {
  const extraAttribute = modelValue.showAttribute?.extraAttribute || ({} as ExtraAttribute);
  const direction = extraAttribute.direction || "";
  const flowPropertyDirection = extraAttribute.flowPropertyDirection || "";
  const isDerived = extraAttribute.isDerived ? "/" : "";
  const name = modelValue.showAttribute?.displayName || modelValue.name;
  const typeName = extraAttribute.typeName ? `:  ${extraAttribute.typeName}` : "";
  const multiplicity = extraAttribute.multiplicity ? `[${extraAttribute.multiplicity}]` : "";
  const defaultValue = extraAttribute.defaultValue ? `= ${extraAttribute.defaultValue}` : "";
  return direction + " " + flowPropertyDirection + " " + isDerived + " " + name + " " + typeName + " " + multiplicity + " " + defaultValue;
};

const getInstanceSpecificationLabel = (modelValue: ModelValue) => {
  const extraAttribute = modelValue.showAttribute?.extraAttribute || ({} as ExtraAttribute);
  const classifierName = extraAttribute.classifierName ? `${extraAttribute.classifierName.join(",")}` : "";
  const name = modelValue.showAttribute?.displayName || modelValue.name;

  return name + " :" + classifierName;
};

const getInstanceLabel = (modelValue: ModelValue) => {
  const extraAttribute = modelValue.showAttribute?.extraAttribute || ({} as ExtraAttribute);
  const name = modelValue.showAttribute?.displayName || modelValue.name;
  const slotLabel = extraAttribute?.slotLabel || "";
  return name + slotLabel;
};

/**
 * 存储表格的行id，以及单元格值的modelid，以计算哪些行需要被刷新
 */
export function useTableFreshModelKeys() {
  // 因为某些属性的更新不在JAVA_MODEL_CHANGE中，因此需要维护一个rowkey => property model id的数据结构
  let rowKeyToPropertyModelKeys: { [key: string]: Set<string> } = {};
  let propertyModelKeyToRowKeys: { [key: string]: Set<string> } = {};
  let columnPropertyKeys: Set<string>;

  const handleAddPropertyModelKeys = (rowKey: string, propertyRow: PropertyRow, highLightContent: HighLightContent[]) => {
    if (propertyRow.slotId) {
      addRowKeyAndPropertyModelKeys(rowKey, propertyRow.slotId);
      propertyRow.values?.forEach(item => {
        addRowKeyAndPropertyModelKeys(rowKey, item.id);
        if (propertyRow.dataType === PropertyDataType.INSTANCE) {
          addRowKeyAndPropertyModelKeys(rowKey, item.value);
        }
      });
    } else {
      highLightContent.forEach(content => {
        if (content.isModel) {
          addRowKeyAndPropertyModelKeys(rowKey, content.modelId as string);
        }
      });
    }
  };

  const addRowKeyAndPropertyModelKeys = (rowKey: string, modelKey: string) => {
    if (!rowKeyToPropertyModelKeys[rowKey]) {
      rowKeyToPropertyModelKeys[rowKey] = new Set();
    }
    const propertyModelKey = rowKeyToPropertyModelKeys[rowKey];
    propertyModelKey.add(modelKey);
    if (!propertyModelKeyToRowKeys[modelKey]) {
      propertyModelKeyToRowKeys[modelKey] = new Set();
    }
    propertyModelKeyToRowKeys[modelKey].add(rowKey);
    //
  };

  const clearPropertyModelKeysByRowKey = (rowKey: string) => {
    const propertyModelKey = rowKeyToPropertyModelKeys[rowKey];
    if (!propertyModelKey) return;
    propertyModelKey.forEach(modelKey => {
      propertyModelKeyToRowKeys[modelKey].delete(rowKey);
    });
    rowKeyToPropertyModelKeys[rowKey] = new Set();
    //
  };

  const clearAllPropertyModelKeys = () => {
    rowKeyToPropertyModelKeys = {};
    propertyModelKeyToRowKeys = {};
  };

  const getRowKeyByPropertyKey = (key: string) => {
    return propertyModelKeyToRowKeys[key];
  };

  const getColumnPropertyKeys = () => {
    return columnPropertyKeys;
  };

  const resetColumnPropertyKeys = (keys: string[]) => {
    columnPropertyKeys = new Set(keys);
  };

  return {
    handleAddPropertyModelKeys,
    addRowKeyAndPropertyModelKeys,
    clearPropertyModelKeysByRowKey,
    clearAllPropertyModelKeys,
    getRowKeyByPropertyKey,
    getColumnPropertyKeys,
    resetColumnPropertyKeys
  };
}
